﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace CRFEncoder
{
    class EncoderFeatureIndex : FeatureIndex
    {
        public EncoderFeatureIndex(int n)
        {
            thread_num_ = n;
        }
        public void shrink(int freq)
        {
            if (freq <= 1)
            {
                return;
            }

            Console.WriteLine("Shrinking features which freq is less than {0}", freq);

            Dictionary<int, int> old2new = new Dictionary<int, int>();
            int new_maxid = 0;
            List<string> removedFeatureList = new List<string>();
            foreach (KeyValuePair<string, FeatureIdPair> it in dic_)
            {
                string strFeature = it.Key;
                if (it.Value.Value >= freq)
                {
                    old2new.Add(it.Value.Key, new_maxid);
                    dic_[strFeature].Key = new_maxid;
                    new_maxid += (strFeature[0] == 'U' ? y_.Count : y_.Count * y_.Count);
                }
                else
                {
                    removedFeatureList.Add(strFeature);
                }
            }
            foreach (string strFeature in removedFeatureList)
            {
                dic_.Remove(strFeature);
            }
 
            for (int i = 0;i < feature_cache_.Count;i++)
            {
                List<int> newfs = new List<int>();
                foreach(int v in feature_cache_[i])
                {
                    if (old2new.ContainsKey(v) == true)
                    {
                        newfs.Add(old2new[v]);
                    }
                }
                feature_cache_[i] = newfs.ToArray();
            }

            Console.WriteLine("Shrink feature from {0} to {1}", maxid_, new_maxid);
            maxid_ = new_maxid;
            return;
        }



        public bool open(string filename1, string filename2)
        {
            return openTemplate(filename1) && openTagSet(filename2);
        }


        public bool saveHeader(string filename)
        {
            StreamWriter tofs = new StreamWriter(filename);

            int version_ = 100;
            // header
            tofs.WriteLine("version: " + version_);
            tofs.WriteLine("cost-factor: " + cost_factor_);
            tofs.WriteLine("maxid: " + maxid_);
            tofs.WriteLine("xsize: " + xsize_);

            tofs.WriteLine();

            // y
            for (int i = 0; i < y_.Count; ++i)
            {
                tofs.WriteLine(y_[i]);
            }
            tofs.WriteLine();

            // template
            for (int i = 0; i < unigram_templs_.Count; ++i)
            {
                tofs.WriteLine(unigram_templs_[i]);
            }
            for (int i = 0; i < bigram_templs_.Count; ++i)
            {
                tofs.WriteLine(bigram_templs_[i]);
            }
            tofs.WriteLine();

            // dic
            foreach (KeyValuePair<string, FeatureIdPair> it in dic_)
            {
                tofs.WriteLine(it.Value.Key + " " + it.Key);
            }

            tofs.WriteLine();
            tofs.Close();

            return true;
        }


        public bool saveBody(string filename)
        {
            StreamWriter tofs = new StreamWriter(filename, true);
            for (int i = 1; i <= maxid_; ++i)
            {
                tofs.WriteLine(alpha_[i]);
            }
            tofs.Close();
            return true;
        }

        bool openTemplate(string filename)
        {
            StreamReader ifs = new StreamReader(filename);
            unigram_templs_ = new List<string>();
            bigram_templs_ = new List<string>();
            while (ifs.EndOfStream == false)
            {
                string line = ifs.ReadLine();
                if (line.Length == 0 || line[0] == '#')
                {
                    continue;
                }
                if (line[0] == 'U')
                {
                    unigram_templs_.Add(line);
                }
                else if (line[0] == 'B')
                {
                    bigram_templs_.Add(line);
                }
                else
                {
                    Console.WriteLine("unknown type: {0}", line);
                }
            }
            ifs.Close();
            return true;
        }

        bool openTagSet(string file)
        {

            StreamReader ifs = new StreamReader(file);

            y_ = new List<string>();
            HashSet<string> hashCand = new HashSet<string>();
            while (ifs.EndOfStream == false)
            {
                string line = ifs.ReadLine();
                if (line.Length == 0 || line[0] == ' ' || line[0] == '\t')
                {
                    continue;
                }
                string[] items = line.Split('\t');
                int size = items.Length;
                xsize_ = size - 1;

                if (hashCand.Contains(items[items.Length - 1]) == false)
                {
                    hashCand.Add(items[items.Length - 1]);
                    y_.Add(items[items.Length - 1]);
                }
            }
            ifs.Close();
            return true;
        }

    }
}
